using System;
using System.Collections.Concurrent;

namespace CSharp.Commons.Pool.Impl
{
    public class GenericItemPool<T> : ItemPool<T>
    {
        private SynchronizedList<T> activeItems;
        private ConcurrentBag<T> idleItems;
        private Func<T> initMethod;
        private Action<T> destoryMethod;

        private bool closing = false;

        public GenericItemPool(Func<T> initMethod, Action<T> destoryMethod)
        {
            if(initMethod == null) throw new ArgumentNullException();
            if(destoryMethod == null) throw new ArgumentNullException();
            
            this.activeItems = new SynchronizedList<T>();
            this.idleItems = new ConcurrentBag<T>();
            this.initMethod = initMethod;
            this.destoryMethod = destoryMethod;
        }
        
        public void addItem()
        {
            if(closing) throw new ObjectDisposedException("GenericItemPool closing...");
            
            T item = this.initMethod.Invoke();
           this.idleItems.Add(item);
        }

        public T borrowItem()
        {
            if(closing) throw new ObjectDisposedException("GenericItemPool closing...");
            
            T item;
            // 尝试从空闲桶中获取item，无法获取创建新item
            if (!this.idleItems.TryTake(out item))
            {
                item = this.initMethod.Invoke();
            }

            // 放入到激活桶
            this.activeItems.Add(item);

            return item;
        }
        
        public int getNumActive()
        {
            return this.activeItems.Count;
        }

        public int getNumIdle()
        {
            return this.idleItems.Count;
        }

        public int getNumTotal()
        {
            return this.getNumActive() + this.getNumIdle();
        }

        public void invalidateItem(T item)
        {
            this.activeItems.Remove(item);
            this.destoryMethod.Invoke(item);
        }

        public void returnItem(T item)
        {
            this.activeItems.Remove(item);
            this.idleItems.Add(item);
        }

        /// <summary>
        ///     关闭对象池，并释放所有资源
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void Dispose()
        {
            this.close();
            this.activeItems.Clear();
        }

        public void close()
        {
            this.closing = true;
            T item;
            
            // 清理空闲的Item
            while (!this.idleItems.IsEmpty)
            {
                this.idleItems.TryTake(out item);
                
                if(item != null) this.destoryMethod.Invoke(item);
            }
            
            // 清理激活的Item
            for (int i = this.activeItems.Count; i > 0; i--)
            {
                item = this.activeItems[i];
                this.activeItems.RemoveAt(i);

                if (item != null) this.destoryMethod.Invoke(item);
            }
        }
    }
}